
import path from 'path';

import { FileSet, Input } from '@ohos/hvigor';
import * as fse from 'fs-extra';
import { create } from 'tar';

import { BuildArtifactExtension } from '../../const/build-directory-const.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { TaskNames } from '../common/task-names.js';
import { TargetTaskService } from '../service/target-task-service.js';
import { OhosHapTask } from '../task/ohos-hap-task.js';
import { PackageSharedHar } from './package-shared-har.js';
import { SignHsp } from './sign-hsp.js';

import Task = TaskNames.Task;

export class PackageSharedTgz extends OhosHapTask {
  private readonly _taskService: TargetTaskService;
  private readonly outputDir: string;
  private readonly RELEASE: string = 'Release';
  private readonly isRelease: boolean;
  private readonly tempSharedHspPath: string;
  private readonly tempSharedHarPath: string;
  private readonly tgzOutPath: string;
  private readonly sharedHspName: string;
  private readonly sharedHspRename: string;
  private readonly sharedHarName: string;
  private readonly sharedHspPath: string;
  private readonly sharedHarPath: string;
  private readonly _log: OhosLogger = OhosLogger.getLogger(PackageSharedTgz.name);

  constructor(taskService: TargetTaskService) {
    super(taskService, Task.PACKAGE_SHARED_TGZ);
    this._taskService = taskService;
    this.outputDir = this.pathInfo.getModuleBuildOutputPath();
    this.isRelease = taskService.getBuildMode() === this.RELEASE;
    this.tgzOutPath = path
      .resolve(this.outputDir, this.targetData.getModuleTargetOutputFileName('', false, BuildArtifactExtension.DOT_TGZ))
      .replace('-unsigned', '');
    const artifactName = this.targetData.getTargetOpt().output?.artifactName;
    const outputName = artifactName ? `${artifactName}` : `${this.moduleName}`;
    this.sharedHspName = this.targetData.getModuleTargetOutputFileName('', false, BuildArtifactExtension.DOT_HSP);
    this.sharedHspRename = this.sharedHspName.replace('-unsigned', '');
    this.sharedHarName = `${outputName}.har`;
    this.tempSharedHspPath = path.resolve(this.pathInfo.getIntermediatesTemp(), this.sharedHspRename);
    this.tempSharedHarPath = path.resolve(this.pathInfo.getIntermediatesTemp(), this.sharedHarName);
    const integratedHsp = !!this.targetService.getBuildOption().arkOptions?.integratedHsp;
    this.sharedHspPath = path.resolve(integratedHsp ? this.pathInfo.getIntegratedHspOutputPath() : this.outputDir, this.sharedHspName);
    this.sharedHarPath = path.resolve(this.outputDir, this.sharedHarName);
  }

  @Input() private get generateSharedTgz() {
    return this.targetService.getBuildOption()?.generateSharedTgz;
  }

  declareInputFiles(): FileSet {
    const fileSet = new FileSet();
    if (fse.existsSync(this.sharedHspPath)) {
      fileSet.addEntry(this.sharedHspPath);
    }
    if (fse.existsSync(this.sharedHarPath)) {
      fileSet.addEntry(this.sharedHarPath);
    }
    return fileSet;
  }

  declareOutputFiles(): FileSet {
    return super.declareOutputFiles().addEntry(this.tgzOutPath, { isDirectory: false });
  }

  initTaskDepends(): void {
    const signHsp = `${this._taskService.getTargetData().getTargetName()}@${SignHsp.name}`;
    const packageSharedHar = `${this._taskService.getTargetData().getTargetName()}@${PackageSharedHar.name}`;
    this.declareDepends(signHsp);
    this.declareDepends(packageSharedHar);
  }

  protected beforeTask() {
    super.beforeTask();
    // 用户没有配置，走原有逻辑
    if (this.generateSharedTgz !== undefined && fse.existsSync(this.tgzOutPath)) {
      fse.removeSync(this.tgzOutPath);
    }
  }

  taskShouldDo(): boolean {
    /**
     * 如果用户没有配置，则走原有的逻辑
     * 如果用户配置了，以用户配置为准
     */
    return this.generateSharedTgz === undefined ? this.isRelease : this.generateSharedTgz;
  }

  /**
   * 只在release模式下执行tgz打包操作
   * @protected
   */
  protected async doTaskAction() {
    await this.buildTgzPackage();
  }

  private async buildTgzPackage(): Promise<void> {
    this.copyTempFiles(this.sharedHspPath, this.tempSharedHspPath);
    this.copyTempFiles(this.sharedHarPath, this.tempSharedHarPath);
    await create(
      {
        cwd: this.pathInfo.getIntermediatesTemp(),
        noDirRecurse: false,
        file: this.tgzOutPath,
        gzip: true,
      },
      [this.sharedHspRename, this.sharedHarName],
    );
    this.removeTempFiles();
  }

  private copyTempFiles(originFile: string, tempFile: string) {
    if (!fse.existsSync(originFile)) {
      this._log.printErrorExit('PACK_TGZ_PACKAGE_FILE_NOT_EXIST', [originFile]);
    }
    if (!fse.existsSync(this.pathInfo.getIntermediatesTemp())) {
      fse.mkdirsSync(this.pathInfo.getIntermediatesTemp());
    }
    fse.copyFileSync(originFile, tempFile);
  }

  private removeTempFiles() {
    fse.removeSync(this.tempSharedHspPath);
    fse.removeSync(this.tempSharedHarPath);
  }
}
